﻿using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SaunaClient.Model.Logger
{
    /// <summary>
    /// Stack Trace Message class that outputs a stack trace message with a user message
    /// </summary>
    /// <remarks>
    /// This class is thread safe. 
    /// </remarks>
    /// <dates>
    /// 15/05/2011 - created by Chiaki Sato
    /// </dates>
    public class StackTraceMessage : ILoggerMessage
    {
        private const string DEFAULT_LOG_DATE_FORMAT = "yyyy/MM/dd HH:mm:ss";
        private const string DEFAULT_STACK_TRACE_FORMAT = "{0} [{1}.{2}() : Line {3}] : ";
        private const int DEFAULT_STACK_INDEX_CALLING_METHOD_UNIT = 2;
        private const int DEFAULT_STACK_INDEX_CALLING_METHOD_COMPO = 3;

        public enum LogType { UNIT = 1, COMPO = 2 }

        private string logDateFormat;
        private string stackTraceFormat;
        private int stackIndexCallingMethod;

        private object lockObject;

        /// <summary>
        /// Default constructor
        /// </summary>
        public StackTraceMessage(LogType logType)
        {
            lockObject = new object();

            this.logDateFormat = DEFAULT_LOG_DATE_FORMAT;
            this.stackTraceFormat = DEFAULT_STACK_TRACE_FORMAT;

            if (logType == LogType.COMPO)
            {
                this.stackIndexCallingMethod = DEFAULT_STACK_INDEX_CALLING_METHOD_COMPO;
            }
            else
            {
                this.stackIndexCallingMethod = DEFAULT_STACK_INDEX_CALLING_METHOD_UNIT;
            }
        }

        /// <summary>
        /// Constructor
        /// <param name="log_date_format">Log date string format</param>
        /// <param name="stack_trace_format">Stack trace string format</param>
        /// <param name="stack_index_calling_method">Stack trace index for calling method</param>
        /// </summary>
        public StackTraceMessage(string logDateFormat, string stackTraceFormat, int stackIndexCallingMethod)
        {
            lockObject = new object();

            this.logDateFormat = logDateFormat;
            this.stackTraceFormat = stackTraceFormat;
            this.stackIndexCallingMethod = stackIndexCallingMethod;
        }

        /// <summary>
        /// Create a complete log message with a stack trace message
        /// </summary>
        /// <param name="message">User log message</param>
        /// <remarks>
        /// From MSDN: Any public static members of StackTrace class are thread safe. 
        /// Any instance members of it are not guaranteed to be thread safe. 
        /// </remarks>
        public string CreateLogMessage()
        {
            lock (lockObject)
            {
                StackTrace stackTrace = new StackTrace(true);

                string stackTraceLogMessage = string.Format(stackTraceFormat
                    , DateTime.Now.ToString(logDateFormat)
                    , stackTrace.GetFrame(stackIndexCallingMethod).GetMethod().ReflectedType.FullName
                    , stackTrace.GetFrame(stackIndexCallingMethod).GetMethod().Name
                    , stackTrace.GetFrame(stackIndexCallingMethod).GetFileLineNumber().ToString()
                    );

                return stackTraceLogMessage;
            }
        }
    }
}
